package com.ruoyi.common.datascope.aspect;

import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.BaseDataScopeEntity;
import com.ruoyi.common.datascope.annotation.DataScope;
import com.ruoyi.common.datascope.service.AwaitUserService;
import com.ruoyi.system.api.model.dto.SysDeptDto;
import com.ruoyi.system.api.model.dto.SysRoleDto;
import com.ruoyi.system.api.model.dto.UserInfo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * 数据过滤处理
 *
 * @author ruoyi
 */
@Aspect
@Component
public class DataScopeAspect {
    /**
     * 全部数据权限
     */
    public static final String DATA_SCOPE_ALL = "1";

    /**
     * 自定数据权限
     */
    public static final String DATA_SCOPE_CUSTOM = "2";

    /**
     * 部门数据权限
     */
    public static final String DATA_SCOPE_DEPT = "3";

    /**
     * 部门及以下数据权限
     */
    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";

    /**
     * 仅本人数据权限
     */
    public static final String DATA_SCOPE_SELF = "5";

    @Autowired
    private AwaitUserService awaitUserService;

    /**
     * 数据范围过滤
     *
     * @param joinPoint 切点
     * @param user      用户
     * @param deptAlias 部门别名
     * @param userAlias 用户别名
     * @param miniScope 最小访问范围
     */
    public static void dataScopeFilter(JoinPoint joinPoint, UserInfo user, String deptAlias, String userAlias, String miniScope) {
        StringBuilder sqlString = new StringBuilder();

        //0 为系统
        if (user.getUserId() != 0) {
            String userDataScope = user.getUserDataScope();
            //用户自定义
            if (DATA_SCOPE_CUSTOM.equals(userDataScope)) {
                List<SysDeptDto> depts = user.getDeptList();
                Long[] deptIds = new Long[depts.size()];
                for (int i = 0; i < depts.size(); i++) {
                    deptIds[i] = depts.get(i).getDeptId();
                }
                String deptIdsStr = StringUtils.join(deptIds, ",");
                sqlString.append(StringUtils.format(
                        " OR {}.dept_id IN ( {} ) ", deptAlias, deptIdsStr));
            } else {
                for (SysRoleDto role : user.getRoleList()) {
                    String dataScope = role.getDataScope();
                    if (!"".equals(miniScope)) {
                        //当当前的访问范围小于最小访问范围的时候默认为最小访问范围
                        dataScope = Integer.parseInt(dataScope) > Integer.parseInt(miniScope) ? miniScope : dataScope;
                    }

                    if (DATA_SCOPE_ALL.equals(dataScope)) {
                        sqlString = new StringBuilder();
                        break;
                    } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) {
                        sqlString.append(StringUtils.format(
                                " OR {}.dept_id IN ( {} ) ", deptAlias, getDeptIdsByDataScopeType(role, DATA_SCOPE_CUSTOM)));
                    } else if (DATA_SCOPE_DEPT.equals(dataScope)) {
                        sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
                    } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
                        sqlString.append(StringUtils.format(
                                " OR {}.dept_id IN ( {} )",
                                deptAlias, getDeptIdsByDataScopeType(role, DATA_SCOPE_DEPT_AND_CHILD)));
                    } else if (DATA_SCOPE_SELF.equals(dataScope)) {
                        if (StringUtils.isNotBlank(userAlias)) {
                            sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
                        } else {
                            // 数据权限为仅本人且没有userAlias别名不查询任何数据
                            sqlString.append(" OR 1=0 ");
                        }
                    }
                }
            }

        }

        if (StringUtils.isNotBlank(sqlString.toString())) {
            BaseDataScopeEntity baseEntity = (BaseDataScopeEntity) joinPoint.getArgs()[0];
            baseEntity.setDataScope(" AND (" + sqlString.substring(4) + ")");
        }
    }

    /**
     * 根据权限范围类型获取权限范围  如果数据为空范围"0"
     *
     * @param role
     * @param dataScopeType
     * @return
     */
    private static String getDeptIdsByDataScopeType(SysRoleDto role, String dataScopeType) {
        String deptIds = "";
        Map<String, Set<Long>> dataScopes = role.getDataScopes();
        if (dataScopes != null) {
            Set<Long> dataScopeCustom = dataScopes.get("type" + dataScopeType);
            if (dataScopeCustom != null && dataScopeCustom.size() > 0) {
                deptIds = StringUtils.join(dataScopeCustom.toArray(), ",");
            }
        }
        if ("".equals(deptIds)) {
            deptIds = "0";
        }
        return deptIds;
    }

    // 配置织入点
    @Pointcut("@annotation(com.ruoyi.common.datascope.annotation.DataScope)")
    public void dataScopePointCut() {
    }

    @Before("dataScopePointCut()")
    public void doBefore(JoinPoint point) throws Throwable {
        handleDataScope(point);
    }

    protected void handleDataScope(final JoinPoint joinPoint) {
        // 获得注解
        DataScope controllerDataScope = getAnnotationLog(joinPoint);
        if (controllerDataScope == null) {
            return;
        }
        // 获取当前的用户
        UserInfo currentUser = awaitUserService.info();
//        SysUser currentUser = loginUser.getSysUser();
        if (currentUser != null) {
            // 如果是超级管理员，则不过滤数据
            if (!currentUser.isAdmin()) {
                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
                        controllerDataScope.userAlias(), controllerDataScope.miniScope());
            }
        }
    }

    /**
     * 是否存在注解，如果存在就获取
     */
    private DataScope getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(DataScope.class);
        }
        return null;
    }
}
